// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "grpc.h"
#include "grpc_data.h"
#include "remote_matrix_wrap.h"

#ifndef FALSE
#define FALSE (1 == 0)
#endif

#ifndef TRUE
#define TRUE (0 == 0)
#endif

extern int ninf_error_code;
int verbose = FALSE;
int configured = FALSE;
int size = -1;

const char tmporary []=  "http://localhost/c.out";

void * setupHandleURL(const char * ref, grpc_data_t * data, int N) {
    grpc_data_init(data,
        (const char * []){ref, NULL},
        (const char * []){ref, NULL},
        GRPC_MATRIX_OF_DOUBLE,
        (size_t []){N, N, 0},
        (grpc_data_mode_t []){GRPC_VOLATILE, GRPC_END_LIST}
    );

  return (void *)data;
}

void * setupHandle(const char * ref, grpc_data_t * data, int N) {
  if (strncmp(ref, "http://", 7) == 0) {
    return setupHandleURL(ref, data, N);
  } else {
    double * ptr;
    int _N, _M;
    _load_matrix(ref, &ptr, &_N, &_M);
    return (void *)ptr;
  }
}

const char * MUL = "matmul/matmul";
const char * SUB = "matmul/matsub";



int matmul_test(const char * refs[3], int N, const char * funname){
  grpc_error_t error;
  grpc_function_handle_t handle;
  grpc_function_handle_default(&handle, funname);
  grpc_data_t data[3];
  
  for (int i = 0; i < 3; i++) 
    fprintf(stderr, "%s\n", refs[i]);


  if ((error = grpc_call(&handle, N, 
			 setupHandle(refs[0], &(data[0]), N),
			 setupHandle(refs[1], &(data[1]), N),
			 setupHandle(refs[2], &(data[2]), N))
       ) != GRPC_NO_ERROR) {
    printf("matmul_test: %s\n", grpc_error_string(error));
    return FALSE;
  }
  return TRUE;
}

void usage(const char * name){
  fprintf(stderr, "USAGE: %s -config CONF_FILE -size MAT_SIZE [FILE | URL] [FILE | URL] URL\n", name);
  exit(1);
}


int main(int argc, const char ** argv){
  const char * name = argv[0];
  const char * refs[3] = {NULL, NULL, NULL};
  const char * func = MUL;
  int i = 0;

  for (; argc > 1;  argc--) {
    argv++;
    if (strcasecmp(*(argv), "-verbose") == 0) {
      verbose = TRUE;
      continue;
    }
    if (strcasecmp(*(argv), "-config") == 0) {
      grpc_initialize(*(++argv));
      configured = TRUE;
      argc--;
      continue;
    }
    if (strcasecmp(*(argv), "-size") == 0) {
      size = atoi(*(++argv));
      argc--;
      continue;
    }
    if (strcasecmp(*(argv), "-sub") == 0) {
      grpc_initialize(*(++argv));
      func = SUB;
      continue;
    }
    //      if (strcasecmp(*(argv), "-debug") == 0)
    //	ninf_debug_flag = TRUE;
    refs[i++] = *argv;
  }
  if (!configured || i < 3 || size < 0)
      usage(name);
      
  if (matmul_test(refs, size, func))  {printf("\tOK\n");} else { printf("\tfailed\n");}
  
  grpc_finalize();

}

